- Görkem Güray/
- 100 Günde SwiftUI Notları/
- 52.Gün - SwiftUI Proje 10 (Cupcake Corner) Challange ve Çözümleri/
52.Gün - SwiftUI Proje 10 (Cupcake Corner) Challange ve Çözümleri
Table of Contents
Umarım bu proje size bildiğiniz becerileri (SwiftUI Picker, Stepper ve Navigation) nasıl kullanacağınızı ve bunları kullanıcının tüm verilerini bir sunucuya gönderen ve yanıtı işleyen bit uygulama haline nasıl getireceğimizi göstermiştir.
Henüz bunun farkında olmayabilirsiniz, ancak projede öğrendiğiniz beceriler iOS geliştiricilerinin büyük çoğunluğu için önemli becerilerdir: kullanıcı verilerini almak, bir sunucuya göndermek ve yanıtı işlemek muhtemelen var olan önemsiz olmayan uygulamaların yarısını oluşturur. Evet, hangi verilerin gönderileceği ve kullanıcı arayüzünü güncellemek için nasıl kullanılacağı büyük ölçüde değişir, ancak kavramlar aynıdır.
Meydan Okuma (Challange) #
Bu uygulamayı ilerletmek için denememiz gereken 3 yol;
- Adres alanlarımız şu anda sadece boşluk olsa bile herhangi bir şey içeriyorsa geçerli kabul ediliyor. Salt boşluk içeren bir string’in geçersiz olduğundan emin olmak için doğrulamayı iyileştirin.
placeOrder()
çağrımız başarısız olursa - örneğin internet bağlantısı yoksa - kullanıcı için bilgilendirici bir uyarı gösterin. Bunu test etmek için, kodunuzdakirequest.httpMethod = "POST"
satırını yorum haline getirebilirsiniz, bu request’i başarısız olmaya zorlayacaktır.- Daha zorlu bir görev için
Order
sınıfını güncellemeyi deneyin, böylece kullanıcının teslimat adresi gibi verileriUserDeafults
’a kaydedebiliriz. Bu biraz düşünmeyi gerektirir, çünkü@AppStorage
burada çalışmaz ve getter ve setter’larınCodable
desteğinde sorunlara neden olduğunu göreceksiniz. Bir orta yol bulabilir misiniz?
Challange Çözümleri #
-
Bu problemi çözmek için
String
üzerinde bir extension yazabiliriz. Bu extension’daallSatisfy()
methodunu kullanarak String’in her bir elemanı üzerinde kontrol yapabiliriz. String’in her bir elemanıCharacter
olduğundan,Character
üzerinde tanımlı bir method olan.isWhitespace
‘i kullanabiliriz. Aşağıdaki kod sayesinde String’e yeni bir method ekleyeceğiz ve bu method sayesinde string tamamen boşluktan (whitespace) oluşuyorsa true değerini geri döneceğiz.extension String { var isBlank: Bool { allSatisfy({$0.isWhitespace}) } }
Yukarıdaki kodu yazdıktan sonra,
Order
sınıfımızdavar hasValidAddress: Bool {
kısmını şu şekilde değiştirebiliriz;if name.isEmpty || name.isBlank || streetAddress.isEmpty || streetAddress.isBlank || city.isEmpty || city.isBlank || zip.isEmpty || zip.isBlank {
-
İnternet bağlantısı ile ilgili bir problem olduğunda bir uyarı göstermek için, öncelikli olarak CheckoutView’da bir değişken oluşturalım;
@State private var showingNoInternet = false
Ardından daha önce oluşturduğumuz
alert
’in altında bir tane daha oluşturalım;.alert("Oops!", isPresented: $showingNoInternet) { Button("OK", role: .cancel) { } } message: { Text("Please check your internet connection.") }
Son olarak
placeOrder()
methodumuzda bulunancatch
bloğuna aşağıdaki kodu ekleyelim;showingNoInternet = true
-
Bu problemin çözümü için öncelikli olarak verileri
UserDefaults
’a nerede veri yazacağımıza karar vermeliyiz. Bunun için en uygun yerAddressView
’daCheckoutView
’ı push ettiğimiz yer olanNavigationLink
bölümüdür. Bu sebeple kodu şu şekilde değiştirin;Section{ NavigationLink("Check out") { CheckoutView(order: order) .onAppear { let addressItems = [order.name, order.streetAddress, order.city, order.zip] if let encoded = try? JSONEncoder().encode(addressItems) { UserDefaults.standard.set(encoded, forKey: "addressItems") print("Address Items kaydedildi.") } } } //NavigationLink } //Section-2
Şimdiki sorun
UserDefaults
’a kaydettiğimiz verileri nerede okuyacağımızdır. Bunun için en uygun yerOrder
sınıfınıninit()
fonksiyonudur. Bu fonksiyondaUserDefaults
’u okuruz eğer kaydedilmiş veri varsa bu verileri sınıf nesnesi yaratılırken ilgili değerlere atarız, eğer veri yoksa boş string atarız. Bunun için Order sınıfında şu değişkenleri tanımladığımız yeri değiştirin;var name: String var streetAddress: String var city: String var zip: String
Ardından aşağıdaki gibi
init()
fonksiyonunu yazın;init() { if let dataName = UserDefaults.standard.data(forKey: "addressItems") { if let decodedName = try? JSONDecoder().decode([String].self, from: dataName) { name = decodedName[0] streetAddress = decodedName[1] city = decodedName[2] zip = decodedName[3] return } } name = "" streetAddress = "" city = "" zip = "" }
Tamamlanmış projeye aşıdaki Github linkinden ulaşabilirsiniz;
Bu yazıyı İngilizce olarak da okuyabilirsiniz.
You can also read this article in English.